/*
 * Copyright 2020-2021 the original author or authors.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      https://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package com.learn.security.oauth2.auth.server.utils;

import com.nimbusds.jwt.JWTClaimsSet;
import com.nimbusds.jwt.SignedJWT;
import lombok.experimental.UtilityClass;
import org.springframework.lang.Nullable;
import org.springframework.security.oauth2.core.endpoint.OAuth2ParameterNames;
import org.springframework.security.oauth2.jose.jws.SignatureAlgorithm;
import org.springframework.security.oauth2.jwt.JoseHeader;
import org.springframework.security.oauth2.jwt.JwtClaimsSet;
import org.springframework.security.oauth2.server.authorization.client.RegisteredClient;
import org.springframework.util.CollectionUtils;
import org.springframework.util.StringUtils;

import java.text.ParseException;
import java.time.Instant;
import java.util.Collections;
import java.util.Set;

/**
 * 源码：{@link org.springframework.security.oauth2.server.authorization.authentication.JwtUtils}
 * 使用的jwt库： https://bitbucket.org/connect2id/nimbus-jose-jwt/src/master/
 *
 * @author knight
 */
@UtilityClass
public class JwtUtils {

	/**
	 * 令牌解析
	 * @param token 令牌
	 * @return {@link JWTClaimsSet}
	 */
	@Nullable
	public JWTClaimsSet parse(String token) {
		try {
			SignedJWT signedJWT = SignedJWT.parse(token);
			return signedJWT.getJWTClaimsSet();
		}
		catch (ParseException e) {
			return null;
		}
	}

	public JoseHeader.Builder headers() {
		return JoseHeader.withAlgorithm(SignatureAlgorithm.RS256);
	}

	/**
	 * 访问令牌的claims
	 * @param registeredClient 注册客户端
	 * @param issuer 发行人
	 * @param subject 主题
	 * @param authorizedScopes 授权范围
	 * @return {@link JwtClaimsSet.Builder}
	 */
	public JwtClaimsSet.Builder accessTokenClaims(RegisteredClient registeredClient, String issuer, String subject,
			Set<String> authorizedScopes) {
		Instant issuedAt = Instant.now();
		Instant expiresAt = issuedAt.plus(registeredClient.getTokenSettings().getAccessTokenTimeToLive());
		// @formatter:off
		JwtClaimsSet.Builder claimsBuilder = JwtClaimsSet.builder();
		if (StringUtils.hasText(issuer)) {
			// 认证信息者的唯一标识(授权服务的地址)
			claimsBuilder.issuer(issuer);
		}
		claimsBuilder
				// 用户
				.subject(subject)
				// clientId
				.audience(Collections.singletonList(registeredClient.getClientId()))
				// 发布时间
				.issuedAt(issuedAt)
				// 过期时间
				.expiresAt(expiresAt)
				.notBefore(issuedAt);
		if (!CollectionUtils.isEmpty(authorizedScopes)) {
			// scope
			claimsBuilder.claim(OAuth2ParameterNames.SCOPE, authorizedScopes);
		}
		// @formatter:on
		return claimsBuilder;
	}

}
